#include "Channel.hpp"

class Connection 
{
public:
    using ptr = shared_ptr<Connection>;
    Connection(const VirtualHost::ptr &host, 
        const ConsumerManager::ptr &cmp, 
        const ProtobufCodecPtr &codec, 
        const muduo::net::TcpConnectionPtr &conn,
        const threadpool::ptr &pool) :
        _conn(conn),
        _codec(codec),
        _cmp(cmp),
        _host(host),
        _pool(pool),
        _channels(make_shared<ChannelManager>())
    {}

    void openChannel(const openChannelRequestPtr &req) 
    {
        //1. 判断信道ID是否重复,创建信道
        bool ret = _channels->openChannel(req->cid(), _host, _cmp, _codec, _conn, _pool);
        if (ret == false) 
        {
            lg(Debug, "创建信道的时候，信道ID重复了");
            return basicResponse(false, req->rid(), req->cid());
        }
        lg(Debug, "%s 信道创建成功！", req->cid().c_str());
        //3. 给客户端进行回复
        return basicResponse(true, req->rid(), req->cid());
    }

    void closeChannel(const closeChannelRequestPtr &req) 
    {
        _channels->closeChannel(req->cid());
        return basicResponse(true, req->rid(), req->cid());
    }

    Channel::ptr getChannel(const string &cid) 
    {
        return _channels->getChannel(cid);
    }

private:
    void basicResponse(bool ok, const string &rid, const string &cid) 
    {
        MessageQueue::basicCommonResponse resp;
        resp.set_rid(rid);
        resp.set_cid(cid);
        resp.set_ok(ok);
        _codec->send(_conn, resp);
    }

private:
    muduo::net::TcpConnectionPtr _conn;
    ProtobufCodecPtr _codec;
    ConsumerManager::ptr _cmp;
    VirtualHost::ptr _host;
    threadpool::ptr _pool;
    ChannelManager::ptr _channels;
};

class ConnectionManager 
{
public:
    using ptr = shared_ptr<ConnectionManager>;
    ConnectionManager() 
    {}

    void newConnection(const VirtualHost::ptr &host, 
        const ConsumerManager::ptr &cmp, 
        const ProtobufCodecPtr &codec, 
        const muduo::net::TcpConnectionPtr &conn,
        const threadpool::ptr &pool) 
    {
        unique_lock<mutex> lock(_mutex);
        auto it = _conns.find(conn);
        if (it != _conns.end()) 
        {
            return ;
        }
        Connection::ptr self_conn = make_shared<Connection>(host, cmp, codec, conn, pool);
        _conns.insert(make_pair(conn, self_conn));
    }

    void delConnection(const muduo::net::TcpConnectionPtr &conn) 
    {
        unique_lock<mutex> lock(_mutex);
        _conns.erase(conn);
    }

    Connection::ptr getConnection(const muduo::net::TcpConnectionPtr &conn) 
    {
        unique_lock<mutex> lock(_mutex);
        auto it = _conns.find(conn);
        if (it == _conns.end()) {
            return Connection::ptr();
        }
        return it->second;
    }
private:
    mutex _mutex;
    unordered_map<muduo::net::TcpConnectionPtr, Connection::ptr> _conns;
};